﻿define(['bokeh'], function (bokeh) {
    var pageId = "4075843";//Primary key of object, so client-pages are grouped by the object being edited
    var remoteValues = {};

    var synx = $.connection.synx;

    var elementHasFocus = function (element) {
        var focusedElement = $(":focus");
        if (focusedElement.length == 0 || focusedElement[0] != element[0]) {
            return false;
        }
        return true;
    };

    //LOCK
    synx.client.lock = function (fieldId, userid, lockrevision) {
        if (remoteValues[fieldId].lockrevision <= lockrevision) {
            remoteValues[fieldId].lockrevision = lockrevision;
            var elementToLock = $(remoteValues[fieldId].element);
            if (!elementHasFocus(elementToLock)) {

                $(elementToLock).attr('title', 'lockefd');
                $(elementToLock).tooltip({
                    relative: true,
                    position: {
                        at: "right center",
                        my: "left+15 center",

                        collision: "flip"


                    },
                    content: function () {
                        return userid == "" ?
                            "locked" :
                            "locked by " + userid;
                    }
                }).show().tooltip("open");
                $(elementToLock).data("tooltipset", true);
                elementToLock.attr('disabled', 'disabled');
            }
        }
    };

    var lock = function (fieldId) {
        ensureConnection(function () {
            var revision = ++remoteValues[fieldId].lockrevision;
            synx.server.lock(fieldId, revision);

        });
    };

    //UNLOCK
    synx.client.unLock = function (fieldId, lockrevision) {
        if (remoteValues[fieldId].lockrevision <= lockrevision) {
            remoteValues[fieldId].lockrevision = lockrevision;
            var elementToUnLock = $(remoteValues[fieldId].element);
            if ($(elementToUnLock).data("tooltipset")) {
                elementToUnLock.removeAttr('disabled');
                elementToUnLock.tooltip("destroy");
                $(elementToUnLock).data("tooltipset", false);
            }
        }
    };

    var unLock = function (fieldId) {
        ensureConnection(function () {
            var revision = ++remoteValues[fieldId].lockrevision;
            synx.server.unLock(fieldId, revision);
        });
    };

    //UPDATE
    synx.client.update = function (fieldId, value, revision) {
        if (remoteValues[fieldId].revision <= revision) {
            remoteValues[fieldId].revision = revision;
            remoteValues[fieldId].data(value);
        }
    };

    synx.client.batchUpdate = function (updates) {
        $.each(updates, function (updateIndex, updateItem) {
            if (updateItem.lockrevision >= 0) {
                if (updateItem.isLocked) {
                    synx.client.lock(updateItem.fieldId, updateItem.lockedBy, updateItem.lockrevision);
                } else {
                    synx.client.unLock(updateItem.fieldId, updateItem.lockrevision);
                }
            }

            if (updateItem.hoverrevision >= 0) {
                if (updateItem.isHovered) {
                    synx.client.hover(updateItem.fieldId, updateItem.hoverrevision);
                } else {
                    synx.client.leave(updateItem.fieldId, updateItem.hoverrevision);
                }
            }

            if (updateItem.revision >= 0) {
                synx.client.update(updateItem.fieldId, updateItem.value, updateItem.revision);
            }
        });
    };

    var update = function (fieldId, value) {
        ensureConnection(function () {
            var revision = ++remoteValues[fieldId].revision;
            synx.server.update(fieldId, value, revision);
        });
    };

    var callbackWhenConnected = [];

    synx.client.updateServer = function () {
        $.each(callbackWhenConnected, function (callBackIndex, callBackItem) {
            if (callBackItem !== null && callBackItem !== undefined)
                callBackItem();
        });
        callbackWhenConnected = [];
    };

    //HOVER
    synx.client.hover = function (fieldId, hoverrevision) {
        if (remoteValues[fieldId].hoverrevision < hoverrevision) {
            remoteValues[fieldId].hoverrevision = hoverrevision;
            var elementToStyle = $(remoteValues[fieldId].element);
            $(elementToStyle).addClass('synxhover', 10);
        }
    };

    synx.client.leave = function (fieldId, hoverrevision) {
        if (remoteValues[fieldId].hoverrevision < hoverrevision) {
            remoteValues[fieldId].hoverrevision = hoverrevision;
            var elementToStyle = $(remoteValues[fieldId].element);
            $(elementToStyle).removeClass('synxhover', 10);
        }
    };

    var leave = function (fieldId) {
        var hoverrevision = ++remoteValues[fieldId].hoverrevision;
        ensureConnection(function () {
            synx.server.leave(fieldId, hoverrevision);
        });
    };

    var hover = function (fieldId) {
        var hoverrevision = ++remoteValues[fieldId].hoverrevision;

        ensureConnection(function () {
            synx.server.hover(fieldId, hoverrevision);
        });

    };

    //BOKEH
    synx.client.bokeh = function (target, top, left, size, r, g, b) {
        bokeh.createBokeh(target, top, left, size, r, g, b);
    };

    var sendBokeh = function (target, top, left, size, r, g, b) {
        ensureConnection(function () {
            synx.server.bokeh(target, top, left, size, r, g, b);
        });
    };

    var sendChat = function (message) {
        ensureConnection(function () {
            chatMessageList.push("Me: " + message);
            synx.server.sendChat(message);
        });
    };

    var chatMessageList = ko.observableArray();
    synx.client.acceptChat = function (message, user) {
        chatMessageList.push("Other: " + message);
    };

    //CONFLICT
    synx.client.resolve = function (fieldId, myValue, otherValue, otherRevision) {

        var buttons = {};
        buttons[myValue] = function () {
            remoteValues[fieldId].revision = otherRevision;
            $(this).dialog("close");
            $(this).dialog("destroy");
            update(fieldId, myValue);

        };
        buttons[otherValue] = function () {
            remoteValues[fieldId].revision = otherRevision;
            $(this).dialog("close");
            $(this).dialog("destroy");

            synx.client.update(fieldId, otherValue, otherRevision);
            $(remoteValues[fieldId].element).val(otherValue);
        };


        $("#resolveDialog").dialog({
            resizable: false,
            modal: true,
            width: 400,
            buttons: buttons
        });

        $("#resolveDialog").dialog("open");
    };


    var ensureConnection = function (callback) {
        if (synx.connection.state == 1) {
            callback();
        } else {
            $.connection.hub.start();
            callbackWhenConnected.push(callback);
        }
    };


    synx.logging = true;
    synx.connection.error(function (error) {
        $("#messages").append("<li>" + error + "</li>");
    });

    synx.connection.connectionSlow(function () {
        $("#messages").append("<li>Synx connection slow</li>");
    });

    synx.connection.stateChanged(function (data) {
        switch (data.newState) {
            case 0:
                $("#connection").text("Connecting");
                break;
            case 1:
                $("#connection").text("Connected");
                synx.server.register(pageId);
                break;
            case 2:
                $("#connection").text("Reconnecting");
                break;
            case 4:
                $("#connection").text("Disconnected");
                $.connection.hub.start();
                break;
            default:
        }
    });

    ensureConnection(function () { });

    ko.bindingHandlers.synxvalue = {
        init: function (element, valueAccessor) {
            remoteValues[valueAccessor().id] = {
                element: element,
                data: valueAccessor().data,
                revision: 0,
                lockrevision: 0,
                hoverrevision: 0,
                isLocked: false,
                isHovered: false,
                lockedBy: ""
            };

            $(element).change(function () {
                valueAccessor().data($(element).val());
                update(valueAccessor().id, valueAccessor().data());
            });

            $(element).focus(function () {
                lock(valueAccessor().id);
            });

            $(element).blur(function () {
                unLock(valueAccessor().id);
            });

        },
        update: function (element, valueAccessor) {
            if (!elementHasFocus($(element))) {
                $(element).val(valueAccessor().data());
            }
        }
    };

    //TODO: fast typing can result in messages being passed unorderd causing the conflict dialog to show
    ko.bindingHandlers.synxrealtime = {
        init: function (element, valueAccessor) {
            remoteValues[valueAccessor().id] = {
                element: element,
                data: valueAccessor().data,
                revision: 0,
                lockrevision: 0,
                hoverrevision: 0,
                isLocked: false,
                isHovered: false,
                lockedBy: ""
            };

            $(element).change(function () {
                valueAccessor().data($(element).val());
                update(valueAccessor().id, valueAccessor().data());
            });

            $(element).keyup(function () {
                valueAccessor().data($(element).val());
                update(valueAccessor().id, valueAccessor().data());
            });

            $(element).focus(function () {
                lock(valueAccessor().id);
            });

            $(element).blur(function () {
                unLock(valueAccessor().id);
            });

        },
        update: function (element, valueAccessor) {
            if (!elementHasFocus($(element))) {
                $(element).val(valueAccessor().data());
            }
        }
    };

    ko.bindingHandlers.synxhover = {
        init: function (element, valueAccessor) {
            $(element).mouseenter(
                function () { hover(valueAccessor().id); });
            $(element).mouseleave(
                function () { leave(valueAccessor().id); });
        }
    };

    return {
        sendBokeh: sendBokeh,
        sendChat: sendChat,
        allChatMessages: chatMessageList
    };

});